package com.aiwiown.snackmq.api;

import com.aiwiown.snackmq.api.exception.SnackMQClientException;
import com.aiwiown.snackmq.common.message.Message;

import java.util.List;

/**
 * 消费者接口
 */
public interface Consumer extends AutoCloseable {
    /**
     * 启动消费者
     */
    void start() throws SnackMQClientException;

    /**
     * 订阅一个主题
     *
     * @param topic    主题名称
     * @param listener 消息监听器，用于处理接收到的消息
     */
    void subscribe(String topic, MessageListener listener);

    /**
     * 【新增】订阅一个主题，并使用批量监听器处理消息
     *
     * @param topic    主题名称
     * @param listener 批量消息监听器
     */
    void subscribe(String topic, BatchMessageListener listener);

    /**
     * 【新增】以严格顺序模式订阅一个主题。
     * SnackMQ 将保证每个分区内的消息按顺序被单个线程消费。
     *
     * @param topic    主题名称
     * @param listener 顺序消息监听器
     */
    void subscribe(String topic, OrderedMessageListener listener);

    /**
     * 【新增】订阅一个主题，并根据过滤表达式在 Broker 端进行消息过滤。
     *
     * @param topic            主题名称
     * @param filterExpression 过滤表达式，例如 "tag = 'VIP'"
     * @param listener         消息监听器
     */
    void subscribe(String topic, String filterExpression, MessageListener listener);

    /**
     * 【新增】订阅一个主题，并使用批量监听器处理消息，并使用过滤表达式在 Broker 端进行消息过滤。
     *
     * @param topic            主题名称
     * @param filterExpression 批量消息监听器
     * @param listener         批量消息监听器
     */
    void subscribe(String topic, String filterExpression, BatchMessageListener listener);

    /**
     * 【新增】订阅一个主题，并使用严格顺序监听器处理消息，并使用过滤表达式在 Broker 端进行消息过滤。
     *
     * @param topic            主题名称
     * @param filterExpression 顺序消息监听器
     * @param listener         顺序消息监听器
     */
    void subscribe(String topic, String filterExpression, OrderedMessageListener listener);

    /**
     * 【新增】以 Pull 模式从指定主题拉取一批消息。
     * 此方法为同步阻塞调用。位点将由客户端自动管理。
     *
     * @param topic       主题名称
     * @param maxMessages 本次拉取最大消息数
     * @param timeoutMs   本次拉取的超时时间（毫秒）
     * @return 拉取到的消息列表，如果超时或没有新消息则返回空列表。
     * @throws SnackMQClientException 如果发生网络或服务端错误
     */
    List<Message> pullList(String topic, int maxMessages, long timeoutMs) throws SnackMQClientException;

    /**
     * 【新增】以 Pull 模式从指定主题和指定分区的指定offset开始拉取一批消息。
     * 此方法为同步阻塞调用。位点将由客户端自动管理。
     *
     * @param topic       主题名称
     * @param partition   分区ID
     * @param offset      从该offset之后开始拉取消息
     * @param maxMessages 本次拉取最大消息数
     * @param timeoutMs   本次拉取的超时时间（毫秒）
     * @return 拉取到的消息列表，如果超时或没有新消息则返回空列表。
     * @throws SnackMQClientException 如果发生网络或服务端错误
     */
    List<Message> pullList(String topic, int partition, long offset, int maxMessages, long timeoutMs) throws SnackMQClientException;

    /**
     * 【修改】以 Pull 模式从指定主题拉取一批消息。
     * 此方法为同步阻塞调用。位点需要用户手动提交。
     *
     * @param topic       主题名称
     * @param maxMessages 本次拉取最大消息数
     * @param timeoutMs   本次拉取的超时时间（毫秒）
     * @return 拉取结果，包含消息列表和下次建议拉取的位点。
     * @throws SnackMQClientException 如果发生网络或服务端错误
     */
    PullResult pullResult(String topic, int maxMessages, long timeoutMs) throws SnackMQClientException;

    /**
     * 【新增】从指定主题、分区和offset开始拉取消息
     *
     * @param topic       要拉取的主题
     * @param partition   分区ID
     * @param offset      从该offset之后开始拉取消息
     * @param maxMessages 最大消息数
     * @param timeoutMs   超时时间
     * @return 拉取结果
     * @throws SnackMQClientException 如果发生不可恢复的错误
     */
    PullResult pullResult(String topic, int partition, long offset, int maxMessages, long timeoutMs) throws SnackMQClientException;

    /**
     * 【新增】为 Pull 模式手动提交位点。
     * 这是一个同步阻塞调用。
     *
     * @param message 要提交位点的最后一条已成功处理的消息。
     * @throws SnackMQClientException 如果提交失败。
     */
    void commitOffset(Message message) throws SnackMQClientException;
}